/**
 * @file bull_hal_net_mqtt.c
 * @brief 
 * @author yejing (yejh@gongniu.cn)
 * @version 1.0
 * @date 2024-05-22
 * 
 * Copyright 2024-2025 GongNiu Inc. All Rights Reserved.
 * 
 */

#include "bull_hal_net_mqtt.h"
#include "bull_hal_sys_memory.h"

#include "mqtt_client.h"
#include "esp_log.h"


#define MQTT_EVENT_ID(S) \
    ((S) == MQTT_EVENT_CONNECTED ? "MQTT_EVENT_CONNECTED" : \
    ((S) == MQTT_EVENT_DISCONNECTED ? "MQTT_EVENT_DISCONNECTED" : \
    ((S) == MQTT_EVENT_SUBSCRIBED ? "MQTT_EVENT_SUBSCRIBED" : \
    ((S) == MQTT_EVENT_UNSUBSCRIBED ? "MQTT_EVENT_UNSUBSCRIBED" : \
    ((S) == MQTT_EVENT_DATA ? "MQTT_EVENT_DATA" : \
    ((S) == MQTT_EVENT_ERROR ? "MQTT_EVENT_ERROR" : \
    "Unknown"))))))


static const char* HAL_MQTT = "hal_mqtt_net";

/**
 * @brief MQTT 事件处理程序
 * 
 * @param event 
 * @return esp_err_t 
 */
static void mqtt_event_handler( void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
    ESP_LOGI( HAL_MQTT, "mqtt event id[%ld]: %s", event_id, MQTT_EVENT_ID(event_id));

    BULL_MQTT_RECEIVE_CB_P handle = ( BULL_MQTT_RECEIVE_CB_P  )handler_args;
    if ( handle == NULL || handle->rev_data_cb == NULL ){
        ESP_LOGE( HAL_MQTT, "mqtt event handler is null");
        return;
    }

    switch ((esp_mqtt_event_id_t)event_id) {

        case MQTT_EVENT_CONNECTED:
            // 连接成功 
            handle->rev_data_cb( BULL_MQTT_EVENT_CONNECTED, NULL, handle->userdata );
            break;

        case MQTT_EVENT_DISCONNECTED:
            // 连接断开
            handle->rev_data_cb( BULL_MQTT_EVENT_DISCONN, NULL, handle->userdata );
            break;

        case MQTT_EVENT_SUBSCRIBED:
            // 订阅主题成功
            handle->rev_data_cb( BULL_MQTT_EVENT_SUBSCRIBED, NULL, handle->userdata );
            break;

        case MQTT_EVENT_UNSUBSCRIBED:
            // 取消订阅主题成功
            handle->rev_data_cb( BULL_MQTT_EVENT_UNSUBSCRIBED, NULL, handle->userdata );
            break;

        case MQTT_EVENT_DATA:
            // 收到数据
            esp_mqtt_event_handle_t event = event_data;
            ESP_LOGI( HAL_MQTT, "TOPIC=%.*s", event->topic_len, event->topic);
            ESP_LOGI( HAL_MQTT, "DATA=%.*s", event->data_len, event->data);

            BULL_MQTT_RECEIVE_T *rev_data = bull_hal_sys_memory_malloc( sizeof( BULL_MQTT_RECEIVE_T ) );
            if( rev_data == NULL ){
                ESP_LOGI( HAL_MQTT, "rev_data malloc error");
                break;
            }

            /******************************************topic data *****************************/
            rev_data->topic_len = event->topic_len;
            rev_data->topic = bull_hal_sys_memory_malloc(event->topic_len+1);
            if(rev_data->topic == NULL){

                ESP_LOGI( HAL_MQTT, "topic malloc error");
                bull_hal_sys_memory_free(rev_data);
                break;
            }

            memset( rev_data->topic,0,event->topic_len+1 );
            memcpy( rev_data->topic,event->topic,event->topic_len );


            rev_data->payload_len = event->data_len;
            rev_data->payload = bull_hal_sys_memory_malloc( event->data_len+1 );
            if( rev_data->payload == NULL ){
                bull_hal_sys_memory_free( rev_data );
                bull_hal_sys_memory_free( rev_data->topic );
                ESP_LOGI( HAL_MQTT, "payload malloc error");
                break;
            }
            memset( rev_data->payload,0,event->data_len+1 );
            memcpy( rev_data->payload,event->data,event->data_len );

            handle->rev_data_cb( BULL_MQTT_EVENT_DATA, rev_data, handle->userdata );

            break;

        case MQTT_EVENT_ERROR:
            // 发生错误
            break;

        default:
            break;
    }
}


/**
 * @brief esp mqtt 订阅主题(单次订阅一个)
 * 
 * @param topic 所订阅主题的topic
 * @return int 
 */
OPERATE_RET bull_hal_net_mqtt_client_sub_single( MQTT_CLIENT_HANDLE mqtt_client_handle, const char *topic, int qos )
{

    return esp_mqtt_client_subscribe_single( mqtt_client_handle, topic, qos );
}

/**
 * @brief 批量订阅主题
 * 
 * @param mqtt_client_handle 
 * @param topic 
 * @param qos 
 * @return OPERATE_RET 
 */
OPERATE_RET bull_hal_net_mqtt_client_sub_multiple( MQTT_CLIENT_HANDLE mqtt_client_handle, const BULL_MQTT_TOPI_LIST_T *topic_list, int size )
{

    return esp_mqtt_client_subscribe_multiple( mqtt_client_handle, (esp_mqtt_topic_t*)topic_list, size );
}

/**
 * @brief 关闭mqtt连接
 * 
 * @return int 
 */
OPERATE_RET bull_hal_net_mqtt_client_destroy( MQTT_CLIENT_HANDLE mqtt_client_handle )
{
    return esp_mqtt_client_destroy( mqtt_client_handle );
}

/**
 * @brief 重新连接MQTT客户端
 * 
 * 该函数用于当MQTT客户端的连接断开后重新建立连接。
 * 
 * @param mqtt_client_handle MQTT客户端的句柄，用于标识唯一的客户端实例。
 * @return OPERATE_RET 返回操作的结果状态码。成功返回操作成功的状态码，失败返回相应的错误状态码。
 */
OPERATE_RET bull_hal_net_mqtt_client_reconnect( MQTT_CLIENT_HANDLE mqtt_client_handle )
{
    return esp_mqtt_client_reconnect( mqtt_client_handle );
}

/**
 * 功能：断开MQTT客户端的连接
 * 参数：
 *      mqtt_client_handle: MQTT客户端的句柄，用于标识和操作特定的MQTT客户端实例。
 * 返回值：
 *      返回操作的结果状态码，具体取值依赖于实现细节，通常成功为正数，错误为负数。
 */
OPERATE_RET bull_hal_net_mqtt_client_disconnect( MQTT_CLIENT_HANDLE mqtt_client_handle )
{
    return esp_mqtt_client_disconnect( mqtt_client_handle );
}


/**
 * @brief 
 * 
 * @param mqtt_client_handle 
 * @return int 
 */
OPERATE_RET bull_hal_net_mqtt_client_start( MQTT_CLIENT_HANDLE mqtt_client_handle )
{
    return esp_mqtt_client_start( mqtt_client_handle );
}

/**
 * @brief 停止MQTT客户端
 * 
 * @param mqtt_client_handle 
 * @return int 
 */
OPERATE_RET bull_hal_net_mqtt_client_stop( MQTT_CLIENT_HANDLE mqtt_client_handle )
{
    return esp_mqtt_client_stop( mqtt_client_handle );
}


/**
 * 
 * @param topic 订阅主题
 * @param data 发送数据
 * @param data_len 发送数据的长度
 * @return int 
 */
OPERATE_RET bull_hal_net_mqtt_client_pub( MQTT_CLIENT_HANDLE mqtt_client_handle, const char* topic, const uint8_t* data, const uint32_t data_len, uint8_t qos, uint8_t retain )
{
    return  esp_mqtt_client_publish( mqtt_client_handle, topic, data, data_len, qos, retain );
}


/**
 * @brief 连接 MQTT 服务器
 * 
 */
OPERATE_RET bull_hal_net_mqtt_init( MQTT_CLIENT_HANDLE *mqtt_client_handle, BULL_HAL_MQTT_REGISTER_T *register_params )
{   

    esp_mqtt_client_config_t mqtt_cfg = { 0 };

    if( register_params == NULL ){

        return OPRT_OS_ADAPTER_INVALID_PARM;
    }

    if ( register_params->uri == NULL )
    {
        return OPRT_OS_ADAPTER_INVALID_PARM;
    }
    
    ESP_LOGI( HAL_MQTT, "url:%s client_id:%s username:%s password:%s", register_params->uri, register_params->client_id, register_params->username, register_params->password);

    mqtt_cfg.broker.address.uri = register_params->uri;
    mqtt_cfg.broker.address.port = register_params->port;

    mqtt_cfg.credentials.client_id = register_params->client_id;
    mqtt_cfg.credentials.username = register_params->username;

    mqtt_cfg.credentials.authentication.password = register_params->password;

    mqtt_cfg.session.keepalive = 10;

    mqtt_cfg.task.priority = 10;
    mqtt_cfg.task.stack_size = 3*4096;

    mqtt_cfg.buffer.size = 1024;
    mqtt_cfg.buffer.out_size = 4096;
    
    esp_mqtt_client_handle_t client_handle = esp_mqtt_client_init( &mqtt_cfg );

    esp_mqtt_client_register_event(client_handle, ESP_EVENT_ANY_ID, mqtt_event_handler, (void *)&( register_params->rev_t ) );

    *mqtt_client_handle = client_handle;

    if ( client_handle == NULL )
    {
        ESP_LOGI( HAL_MQTT, "client_handle error");
        return OPRT_OS_ADAPTER_NETWORK_ERROR;
    }
    
    
    ESP_LOGI( HAL_MQTT, "client_handle init");
    return OPRT_OS_ADAPTER_OK;
}



